📝 Python 连接 MySQL · 习题课

📚 第17章配套练习 🐍 含 Python 代码实操 🎯 期末重点
🎯 本节练习目标
  • 掌握 5 步流程、commit/rollback、fetch 三件套
  • 读懂 Python+MySQL 代码并预测结果
  • 能根据需求 写出 完整的 CRUD 程序
  • 会用 try-except 处理事务,保证数据一致性

📌 答题前先看:标准模板

🎯 5 步标准模板

import mysql.connector # 第1步:导入
db = mysql.connector.connect(...) # 第2步:连接
cursor = db.cursor() # 第3步:游标
try:
    cursor.execute("...") # 第4步:执行
    db.commit() # 改数据要 commit
except:
    db.rollback()
cursor.close() # 第5步:关闭
db.close()

⚠️ 三个最容易丢分的地方

忘了 db.commit() —— INSERT/UPDATE/DELETE 数据没真的写入

没用 try-except —— 出错时数据不一致

fetchone vs fetchall 混用 —— 一个返回元组,一个返回列表

📝 第一部分 · 概念巩固

先用几道选择题把核心概念过一遍。

练习 1.1⭐⭐ 必考5 步流程

Python 连接 MySQL 数据库的 5 步流程,正确顺序 是?

📖 查看答案

✅ 答案:B

速记:"导 → 连 → 游 → 执 → 关"

逻辑:① 先导入包(才能用 mysql.connector);② 用 connect() 建立连接;③ 通过连接创建游标;④ 用游标执行 SQL;⑤ 用完关闭(先关游标后关连接)。

练习 1.2⭐⭐ 必考connect() 参数

下列 不是 mysql.connector.connect() 必须参数的是?

📖 查看答案

✅ 答案:D · port

必须的 4 个参数:host、user、passwd、database

port 可以省略,默认是 3306(MySQL 标准端口)。除非你的 MySQL 装在非标准端口,才需要写。

练习 1.3⭐⭐ 必考commit · 必考核心

下列哪种情况 不需要 调用 db.commit()?

📖 查看答案

✅ 答案:D · SELECT 不需要 commit

口诀:"读不 commit,写必 commit"

SELECT 是读取,没改数据,不需要 commit

INSERT/UPDATE/DELETE 是修改,必须 commit 才会真的写入数据库

不 commit 的修改只在缓冲区,关闭连接后修改全没了

练习 1.4⭐⭐ 中等fetch 系列

关于 fetchone()fetchall(),下列说法 错误 的是?

📖 查看答案

✅ 错的是:C

① fetchall() 把所有结果一次加载到内存,数据量大时会很慢且占内存

② fetchone() 一次只取一行,只想要一行时反而更高效

选择标准:

• 只要一行 → fetchone()

• 要全部且数据量小 → fetchall()

• 数据量大但只要前 N 条 → fetchmany(N)

练习 1.5⭐⭐ 中等rollback 作用

关于 db.rollback(),下列说法 正确 的是?

📖 查看答案

✅ 答案:C

rollback() 的作用是 "撤销":撤销所有没 commit 的修改,让数据库回到上一次 commit 后的状态。

典型场景:批量插入时其中一条出错 → rollback 把前面已经插入的也撤销 → 保证原子性(要么全成,要么全败)

这就是第 9 章学过的"事务原子性"在 Python 里的实现。

📖 第二部分 · 读代码(预测结果)必考

本部分给一段代码,不要急着运行,先动脑分析执行流程,再对照答案。

练习 2.1📖 读代码没 commit 的后果 · 必考

下面的代码运行不会报错,但执行完后再到 MySQL 中查询 s 表,能查到 's13' 这条新记录吗?

🐍 Python
import mysql.connector

db = mysql.connector.connect(
    host='localhost', user='root',
    passwd='123456', database='teaching'
)
cursor = db.cursor()

cursor.execute("INSERT INTO s VALUES('s13','测试','男',20,'软件','信息学院')")

# 注意:这里没有 db.commit()

cursor.close()
db.close()
📖 查看答案

查不到!

原因分析

execute() 执行后,修改只在缓冲区,并没有真的写入 MySQL。必须 db.commit() 才会"提交"到数据库。这段代码没 commit 就 close,缓冲区的修改全部丢失

解决办法

cursor.close() 之前加一行 db.commit()

⚠️ 这是必考点

"忘了 commit"是初学者最容易踩的坑,期末考试也最爱考。记住:"读不 commit,写必 commit"、"提交才落盘,不提白干"

练习 2.2📖 读代码fetch 不同方法

假设 s 表中有 5 个 age >= 20 的学生。下面三段代码 分别打印什么?

🐍 Python · 三段代码
# --- 第 1 段 ---
cursor.execute("SELECT * FROM s WHERE age >= 20")
r1 = cursor.fetchone()
print(type(r1), len(r1) if r1 else 0)

# --- 第 2 段 ---
cursor.execute("SELECT * FROM s WHERE age >= 20")
r2 = cursor.fetchall()
print(type(r2), len(r2))

# --- 第 3 段 ---
cursor.execute("SELECT * FROM s WHERE age >= 20")
r3 = cursor.fetchmany(3)
print(type(r3), len(r3))
📖 查看答案
第 1 段:fetchone()

一行,返回 元组。学生表 s 共 6 个字段。

<class 'tuple'> 6
第 2 段:fetchall()

全部 5 行,返回 列表(列表里是 5 个元组)。

<class 'list'> 5
第 3 段:fetchmany(3)

前 3 行,返回 列表

<class 'list'> 3
💡 三个关键差异

fetchone 返回 tuple,其他两个返回 list

fetchall 取全部,fetchmany(n) 取 n 个

③ 一行的长度 = 字段数量(6),返回的是 列表中元组的个数

练习 2.3📖 读代码try-except 异常

假设 s 表的主码是 sno,且已经存在 's1'。运行下面代码,会输出什么?数据库里 s5 的记录会被插入吗?

🐍 Python
import mysql.connector

db = mysql.connector.connect(
    host='localhost', user='root',
    passwd='123456', database='teaching'
)
cursor = db.cursor()

try:
    # 第 1 条:s5 是新学号(假设原本不存在)
    cursor.execute("INSERT INTO s VALUES('s5','张三','男',20,'计算机','信息学院')")
    
    # 第 2 条:s1 已经存在(主码冲突,会抛异常!)
    cursor.execute("INSERT INTO s VALUES('s1','李四','女',19,'数学','理学院')")
    
    db.commit()
    print("全部插入成功")
except:
    db.rollback()
    print("插入失败已回滚")

cursor.close()
db.close()
📖 查看答案
执行流程

① 第 1 条 INSERT s5 → 没报错(s5 不存在)

② 第 2 条 INSERT s1 → 抛异常(s1 已存在,主码冲突)

③ 跳到 except 块

④ 执行 db.rollback()撤销所有未提交的修改(包括第 1 条的 s5)

⑤ 输出 "插入失败已回滚"

▶ 输出结果插入失败已回滚
数据库状态

s5 不会被插入! 因为 rollback 把第 1 条 INSERT 也撤销了。

💡 这就是事务的原子性

"要么全成功,要么全失败" —— 不会出现"一半成功一半失败"的中间状态。这就是第 9 章学过的事务原子性,在 Python 里的实现。

💻 第三部分 · 写代码必考

本部分要求 根据需求自己写 Python 代码。先在纸上画出框架,再对照答案。

练习 3.1💻 写代码连接 + 简单查询

写一段 Python 代码,连接 teaching 数据库(host=localhost, user=root, passwd=123456),查询学生总数并打印

📖 查看答案

解题思路:① 5 步流程;② SQL: SELECT COUNT(*) FROM s;③ 结果一行一列,用 fetchone()

🐍 Python · 标准答案
import mysql.connector

db = mysql.connector.connect(
    host='localhost',
    user='root',
    passwd='123456',
    database='teaching'
)
cursor = db.cursor()

cursor.execute("SELECT COUNT(*) FROM s")
result = cursor.fetchone()    # 返回元组,如 (12,)
print("学生总数:", result[0])

cursor.close()
db.close()
💡 注意点

① 查询不需要 commit

fetchone() 返回元组,如 (12,),要用 result[0] 取数字

练习 3.2💻 写代码INSERT + try-except

写一段 Python 代码,用 try-except 模板 向 s 表中插入两条记录:

📋 要插入的数据
  1. ('s20', '陈小明', '男', 20, '软件', '信息学院')
  2. ('s21', '李小红', '女', 19, '数学', '理学院')

要求:全部成功才提交;有一条失败就全部回滚。

📖 查看答案
🐍 Python · 标准答案
import mysql.connector

db = mysql.connector.connect(
    host='localhost', user='root',
    passwd='123456', database='teaching'
)
cursor = db.cursor()

sql1 = "INSERT INTO s VALUES('s20','陈小明','男',20,'软件','信息学院')"
sql2 = "INSERT INTO s VALUES('s21','李小红','女',19,'数学','理学院')"

try:
    cursor.execute(sql1)
    cursor.execute(sql2)
    db.commit()      # 全部成功才 commit
    print("全部插入成功")
except Exception as e:
    db.rollback()    # 任何一条失败就回滚
    print("插入失败:", e)

cursor.close()
db.close()
💡 try-except 黄金套路

① 用 try 包住所有的 execute 和 commit

② 用 except 调用 rollback

这样能保证 原子性(要么全成,要么全败)。

练习 3.3💻 写代码UPDATE + rowcount

写一段 Python 代码,把 s 表中所有"信息学院"的学生年龄(age)都增加 1,并打印出影响了多少行

📖 查看答案
🐍 Python · 标准答案
import mysql.connector

db = mysql.connector.connect(
    host='localhost', user='root',
    passwd='123456', database='teaching'
)
cursor = db.cursor()

sql = "UPDATE s SET age = age + 1 WHERE dept = '信息学院'"

try:
    cursor.execute(sql)
    db.commit()
    print("成功更新", cursor.rowcount, "行")
except Exception as e:
    db.rollback()
    print("更新失败:", e)

cursor.close()
db.close()
💡 cursor.rowcount

cursor.rowcount 返回 最近一次 execute 受影响的行数。对 UPDATE/DELETE 特别有用,可以判断"到底有几条记录被改了"。

练习 3.4💻 写代码SELECT + 遍历

写一段 Python 代码,查询 s 表中所有"女"生的学号(sno)和姓名(sn),逐行打印,格式如:s1 | 王彤

📖 查看答案
🐍 Python · 标准答案
import mysql.connector

db = mysql.connector.connect(
    host='localhost', user='root',
    passwd='123456', database='teaching'
)
cursor = db.cursor()

cursor.execute("SELECT sno, sn FROM s WHERE sex = '女'")
results = cursor.fetchall()    # 取所有结果

# 遍历打印
for row in results:
    print(row[0], "|", row[1])

cursor.close()
db.close()
▶ 运行结果(示意)s1 | 王彤 s2 | 苏乐 s4 | 陶然 s6 | 何欣荣 s7 | 赵琳琳
💡 知识点

① 查询不需要 commit

fetchall() 返回 列表,列表里每个元素是一行的元组

③ 元组用下标取字段:row[0] 是 sno,row[1] 是 sn

④ 也可以解包:for sno, sn in results: print(sno, "|", sn) 更优雅

🎯 第四部分 · 综合大题期末重点

本部分把整章知识揉到一起,是 必考综合大题

综合大题⭐⭐⭐ 期末重点学生信息管理

写一个完整的 Python 程序,实现以下需求:

📋 业务需求
  1. 插入一名新学生:('s30','王晓明','男',20,'计算机','信息学院')
  2. 修改"陈小红"的专业为"软件"
  3. 查询并打印所有"信息学院"的学生(逐行显示)
  4. 使用 try-except 处理事务,出错回滚
  5. 所有数据库操作完成后,关闭游标和连接
📖 查看答案

解题思路:

① 一次连接,做三件事(INSERT + UPDATE + SELECT)

② INSERT 和 UPDATE 是修改,需要 commit + try-except

③ SELECT 是查询,不需要 commit

🐍 Python · 完整答案
import mysql.connector

# 第 1 步:连接数据库
db = mysql.connector.connect(
    host='localhost',
    user='root',
    passwd='123456',
    database='teaching'
)
cursor = db.cursor()

# 第 2 步:执行修改类操作(INSERT + UPDATE),用 try-except 保证原子性
try:
    # 插入新学生
    cursor.execute(
        "INSERT INTO s VALUES('s30','王晓明','男',20,'计算机','信息学院')"
    )
    # 修改专业
    cursor.execute(
        "UPDATE s SET maj = '软件' WHERE sn = '陈小红'"
    )
    
    db.commit()
    print("插入和修改成功!")
except Exception as e:
    db.rollback()
    print("操作失败,已回滚:", e)

# 第 3 步:查询所有信息学院学生
print("\n--- 信息学院学生列表 ---")
cursor.execute("SELECT * FROM s WHERE dept = '信息学院'")
results = cursor.fetchall()

for row in results:
    print(row)

# 第 4 步:关闭游标和连接
cursor.close()
db.close()
print("\n程序执行完毕")
▶ 运行结果(示意)插入和修改成功! --- 信息学院学生列表 --- ('s1', '王彤', '女', 18, '计算机', '信息学院') ('s2', '苏乐', '女', 20, '信息', '信息学院') ('s30', '王晓明', '男', 20, '计算机', '信息学院') ... 程序执行完毕
💡 解题要点

"导→连→游→执→关" 5 步流程

② INSERT 和 UPDATE 放在一个 try 里,保证原子性

③ SELECT 单独执行,不在 try 里(查询不需要事务保护)

fetchall() 取全部结果,然后用 for 循环遍历

⚠️ 易错点

① 忘了 db.commit() → 数据没真的写入

② 把 SELECT 也放在 try 里 → 不会出错,但没必要

③ 忘了 close() → 短期没事,长期会耗尽数据库连接资源

📝 复习重点回顾

通过本次练习,你应该已经:

⭐ 期末考点排行榜

按出现频率排序:

  1. 写一段完整的 Python 连 MySQL 代码(综合大题,分值最高)
  2. commit 和 rollback 的作用(必考)
  3. fetchone vs fetchall vs fetchmany 的区别
  4. 5 步流程(顺序题)
  5. 什么时候要 commit(读不要、写要)
💡 5 条核心口诀

"导 → 连 → 游 → 执 → 关" —— 5 步流程

"读不 commit,写必 commit" —— 何时提交

"try 执行 commit,except 写 rollback" —— 标准模板

"fetchone 一行,fetchall 全部" —— 查询方法

"提交才落盘,不提白干" —— commit 的意义

🎓 整门课程完结!

恭喜你完成了《数据库原理及应用教程(MySQL)》整本教材的所有练习!

从第 1 章的关系模型基础,到本章的 Python 编程实战,你已经掌握了:

🎉 期末考个好成绩 💪 全书完